#region license
# This file is part of Grawlix.
# 
# Grawlix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# 
# Grawlix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with Grawlix.  If not, see
# <http://www.gnu.org/licenses/>.
#endregion

"""Convert from string to a collection type."""

namespace Grawlix.Services.Converters
import Grawlix.Services
import C5
import System
import System.Collections.Generic as SCG
import System.Xml

transient class CollectionTypeConverter(ITypeConverter):
"""Convert to a string type from a collection of string types."""
	
	def IsSupported([required] type as Type):
	"""
	Queries whether conversion to the specified type is
	possible with this converter.
	Param type: The type to try to convert to.
	Returns: true if possible, else false
	"""
		if type.IsGenericType and \
			not type.IsGenericTypeDefinition and \
			type.GetGenericArguments().Length == 1 and \
			type.IsInterface:
			generic = type.GetGenericTypeDefinition()
			if generic == typeof(object*). \
				GetGenericTypeDefinition():
				return true
			if generic == typeof(SCG.ICollection[of object]). \
				GetGenericTypeDefinition():
				return true
			if generic == typeof(IList[of object]). \
				GetGenericTypeDefinition():
				return true
		return false
	
	def Convert(
		[required] provider as ServiceProvider,
		[required] data as string,
		[required] type as Type):
	"""
	Converts the given data to the given type, if possible.
	Param provider: The service provider to recurse on, if needed.
	Param data: The string data to convert.
	Param type: The type to try to convert to.
	Returns: The converted object if successful, or null.
	Raises ArgumentException: type is not supported.
	"""
		unless IsSupported(type):
			raise ArgumentException(
				"Specified type (${type}) is not supported.",
				"type")
		paramType = type.GetGenericArguments()[0]
		genericType = typeof(LinkedList[of object])
		genericType = genericType.GetGenericTypeDefinition()
		genericType = genericType.MakeGenericType(paramType)
		list as duck = genericType()
		
		doc = XmlDocument()
		doc.LoadXml("<root>" + data + "</root>")
		node = doc.DocumentElement
		if node.ChildNodes.Count == 0:
			raise Xml.XmlException(
				"Configuration for ${type} parameters should " +
				"contain a non-empty list of nodes with the name 'item' " +
				"and data that converts to ${paramType}.")
		for child as XmlNode in node.ChildNodes:
			if child.Name != "item" or \
				child.Attributes.Count != 0:
				raise Xml.XmlException(
					"Configuration for ${type} parameters should " +
					"contain a non-empty list of nodes with the name 'item' " +
					"and data that converts to ${paramType}.")
			childData = child.InnerXml
			childInstance = \
				provider.TypeConverter.Convert(provider, childData, paramType)
			list.Add(childInstance)
		return list as object
	
	override def ToString():
	"""
	Get a string representation for this object.
	Returns: A string representation for this object.
	"""
		return "CollectionTypeConverter"
	
